#pragma once
#include "Task.hpp"

#include <iostream>
#include <vector>
#include <semaphore.h>
#include <cassert>
#include <pthread.h>

static const int gmaxcap = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(const int &cap = gmaxcap)
        : _queue(cap), _cap(cap)
    {
        int n = sem_init(&_spaceSem, 0, _cap);
        assert(n == 0);
        n = sem_init(&_dataSem, 0, 0);
        assert(n == 0);
        _producerStep = _consumerStep = 0;

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);
    }
    void P(sem_t &sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0); // if
        (void)n;
    }
    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;
    }
    // 生产者
    void Push(const T &in)
    {
        // 先加锁，后申请信号量，还是先申请信号量，后加锁？
        P(_spaceSem); // 申请到了空间信号量，意味着，生产者可以正常生产。
        pthread_mutex_lock(&_pmutex);
        _queue[_producerStep++] = in;
        _producerStep %= _cap;
        V(_dataSem);
        pthread_mutex_unlock(&_pmutex);
    }
    // 消费者
    void Pop(T *out)
    {
        P(_dataSem); // 申请到了数据信号量，意味着，消费者可以正常消费
        pthread_mutex_lock(&_cmutex);
        *out = _queue[_consumerStep++];
        _consumerStep %= _cap;
        V(_spaceSem);
        pthread_mutex_unlock(&_cmutex);
    }
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);

        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }

private:
    std::vector<T> _queue;   // 数组模拟环形队列
    int _cap;                // 环形队列容量
    sem_t _spaceSem;         // 生产者，想生产，看重的是空间资源
    sem_t _dataSem;          // 消费者，想消费，看重的是数据资源
    int _producerStep;       // 生产数据的下标
    int _consumerStep;       // 消费数据的下标
    pthread_mutex_t _pmutex; // 生产者的锁
    pthread_mutex_t _cmutex; // 消费者的锁
};